package lj.netty.websocket;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.StaticLog;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lj.netty.websocket.bo.WebSocketMsgBo;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class WebSocketService {

    public int port;
    private WebSocketHandler webSocketHandler;

    private String basePath = "ws";

    public WebSocketService(int port, WebSocketHandler webSocketHandler) {
        this.port = port;
        this.webSocketHandler = webSocketHandler;
    }

    public WebSocketService(int port, WebSocketHandler webSocketHandler, String basePath) {
        this.port = port;
        this.webSocketHandler = webSocketHandler;
        this.basePath = basePath;
    }

    public void start() throws InterruptedException {
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        EventLoopGroup childGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            //websocket协议本身就是基于http协议的，所以这边也要使用http编解码器
                            pipeline.addLast(new HttpServerCodec());
                            //以块的方式来写处理器,用于大数据的分区传输
                            pipeline.addLast(new ChunkedWriteHandler());
                            pipeline.addLast(new HttpObjectAggregator(8192));
                            pipeline.addLast(new IdleStateHandler(120, 45, 10));
                            pipeline.addLast(webSocketHandler);
                            pipeline.addLast(new WebSocketServerProtocolHandler(StrUtil.format("/{}", basePath), "websocket", true, 65536 * 10));
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            log.info("--->>> 初始化 Netty WebSocket 成功! <<<---");
            channelFuture.channel().closeFuture().sync();
        } finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        WebSocketService webSocketService = new WebSocketService(33610, new WebSocketHandler() {
            @Override
            public String onMsg(WebSocketMsgBo webSocketMsgBo) {
                StaticLog.info(webSocketMsgBo.getMsg());
                return super.onMsg(webSocketMsgBo);
            }
        });
        webSocketService.start();
    }
}
